
#ifdef DH
#include "DHDecoder.h"

#include "../inc/Utils.h"


DHDecoder::DHDecoder(void)
{
	recvThreadRunning = true;
	decodeThreadRunning = true;
	DHInputRunning = true;
	isDHStopped = false;
	DHport = -1;
	playFlag = PLAY;

	recvBuf = (char*)malloc(2048);

	av_register_all();
	avformat_network_init();



	lfds611_queue_new( &qs_pool, QUEUE_SIZE );
	lfds611_queue_new( &qs_packet, QUEUE_SIZE );
	for(int i = 0;i<QUEUE_SIZE;i++)
	{
		PacketBuffer *packetBuffer =(PacketBuffer*)malloc(sizeof(PacketBuffer));;
		packetBuffer->packetBuffer =(unsigned char*)malloc(MAX_PAKCET_SIZE);
		memset(packetBuffer->packetBuffer, 0 , MAX_PAKCET_SIZE);
		lfds611_queue_use(qs_pool);
		lfds611_queue_enqueue( qs_pool, (void *)packetBuffer );
	}
}


DHDecoder::~DHDecoder(void)
{
	if(port != 0)
	{
		_print_log("Finished receiving. Closing socket.\n");
		closesocket(RecvSocket);
		WSACleanup();
	}
	if(recvThread != NULL)
	{
		//TerminateThread(startThread, 0);
		recvThreadRunning = false;
		WaitForSingleObject(recvThread, INFINITE);
		CloseHandle(recvThread);
		recvThread = NULL;
	}

	if(DHInputThread != NULL)
	{
		//TerminateThread(decodeThread, 0);

		DHInputRunning = false;
		PLAY_Stop(DHport);
		PLAY_CloseStream(DHport);
		_print_log("DH SDK released.\n");
		//while(isDHStopped == false)
		//{
		//	Sleep(100);
		//}
		WaitForSingleObject(DHInputThread, INFINITE);
		CloseHandle(DHInputThread);
		DHInputThread = NULL;
	}

	if(decodeThread != NULL)
	{
		//TerminateThread(decodeThread, 0);
		decodeThreadRunning = false;
		WaitForSingleObject(decodeThread, INFINITE);
		CloseHandle(decodeThread);
		decodeThread = NULL;
	}




	free(recvBuf);


	av_frame_free(&frame);

	if(frameBGR != NULL)
		avpicture_free((AVPicture*) frameBGR);
	avformat_network_deinit();

	if(qs_pool != NULL && qs_packet != NULL)
	{
		PSPacketBuffer *buffer = NULL;
		int free_count = 0;
		lfds611_queue_use(qs_pool);

		while(LFDS_SUCCESS == lfds611_queue_dequeue( qs_pool, (void **) &buffer))
		{
			if(buffer->packetBuffer != NULL)
			{
				free(buffer->packetBuffer);
				free_count ++;
				//printf("pool_free_count:%d\n", free_count);
			}
		}
		lfds611_queue_use(qs_packet);
		while(LFDS_SUCCESS == lfds611_queue_dequeue( qs_packet, (void **) &buffer))
		{
			if(buffer->packetBuffer != NULL)
			{
				free(buffer->packetBuffer);
				free_count ++;
				//printf("packet_free_count:%d\n", free_count);
			}
		}
	}
	else
	{// no need for freeing queue;
	}

	_print_log("released\n");

}



//typedef void (CALLBACK* fDecCBFun)(LONG nPort,char * pBuf,LONG nSize,FRAME_INFO * pFrameInfo, void* pUserData, LONG nReserved2);
void CALLBACK DHDecCBFun(LONG nPort,char * pBuf,LONG nSize,
						 FRAME_INFO * pFrameInfo, 
						 void* nReserved1,long /*nReserved2*/)
{
	DHDecoder* instance = (DHDecoder*)nReserved1;
	if ( pFrameInfo->nType == T_IYUV ) 
	{   
		//_print_log("test:: get video data !\n");

		if(instance->frameBGR->data[0] == NULL)
		{
			instance->width = pFrameInfo->nWidth;
			instance->height = pFrameInfo->nHeight;

			instance->frameBGR->width = instance->width;
			instance->frameBGR->height = instance->height;
			instance->frame->width = instance->width;
			instance->frame->height = instance->height;
			//pRGBData = (char*)malloc(width * height * 4);
			instance->pSwsCtxBGR32 = sws_getContext(instance->frame->width, instance->frame->height,
				PIX_FMT_YUV420P, instance->width, instance->height, PIX_FMT_RGB32,SWS_BILINEAR,NULL,NULL,NULL);

			avpicture_alloc((AVPicture*)instance->frameBGR, PIX_FMT_RGB32, instance->width, instance->height);
			avpicture_alloc((AVPicture*)instance->frame, PIX_FMT_YUV420P, instance->width, instance->height);
			//char err[AV_ERROR_MAX_STRING_SIZE];
			//printf("%s\n", av_make_error_string(err, AV_ERROR_MAX_STRING_SIZE, ret));

		}

		memcpy(instance->frame->data[0], pBuf, instance->width * instance->height);
		memcpy(instance->frame->data[1], pBuf + instance->width * instance->height, instance->width *instance->height / 4);
		memcpy(instance->frame->data[2], pBuf + instance->width * instance->height * 5 / 4, instance->width * instance->height / 4);


		int ret = sws_scale(instance->pSwsCtxBGR32, instance->frame->data,instance->frame->linesize,
			0, instance->frame->height,instance->frameBGR->data,instance->frameBGR->linesize);
		if(instance->frameBGR->height != ret)
		{
			_print_log("sws_scale failed\n");
			return;
		}

		instance->frameInfo.width = instance->width;
		instance->frameInfo.height = instance->height;
		(*instance->DecodeCBFun)((char*)instance->frameBGR->data[0], instance->width * instance->height * 4, &instance->frameInfo, instance->pUser);

	}


}

unsigned int _stdcall DHInputRoutine(void* arg)
{
	DHDecoder* instance = (DHDecoder*)arg;

	PSPacketBuffer *buffer;
	lfds611_queue_use(instance->qs_packet);
	int n = 0;
	while(instance->DHInputRunning == true)
	{
		while(LFDS_SUCCESS != lfds611_queue_dequeue( instance->qs_packet, (void **) &buffer))
		{
			if(instance->DHInputRunning == false)
				return 0;
			Sleep(NORMAL_WAIT_TIME);
		}
		//_print_log("%d\n", n);
		if(n == 0)
		{
			if(!PLAY_SetDecCBStream(instance->DHport, 1)) // 1:video
				_print_log("PLAY_SetDecCBStream failed with retcode %d\n", PLAY_GetLastError(instance->DHport));


			_print_log("port:%d, head:%s\n", instance->DHport, buffer->packetBuffer);
			if (!PLAY_OpenStream(instance->DHport, NULL, 0, 1024*1000))

				_print_log("PLAY_OpenStream failed with retcode %d\n", PLAY_GetLastError(instance->DHport));

			if(!PLAY_Play(instance->DHport, NULL))
				_print_log("PLAY_Play failed with retcode %d\n", PLAY_GetLastError(instance->DHport));
		}
		else
		{
			while(TRUE != PLAY_InputData(instance->DHport, buffer->packetBuffer, buffer->bufferSize))
			{
				_print_log("input failed with retcode %d\n", PLAY_GetLastError(instance->DHport));
				if(instance->DHInputRunning == false)
					return 0;
				Sleep(NORMAL_WAIT_TIME);
			}
			while(LFDS_SUCCESS != lfds611_queue_enqueue( instance->qs_pool, (void *) buffer))
			{
				if(instance->DHInputRunning == false)
					return 0;
				Sleep(NORMAL_WAIT_TIME);
			}
		}
		n++;
	}

	instance->isDHStopped = true;
	return 0;
}

void DHDecoder::startRecvThread()
{
	_print_log("Start receiving DH stream.\n");


	while(recvThreadRunning == true)
	{
		if(playFlag == PLAY)
		{
		}
		else if(playFlag == PAUSE)
		{
			Sleep(NORMAL_WAIT_TIME);
			continue;
		}
		else if(playFlag == STOP)
		{
			break;
		}
		else
		{
			_print_log("illegal playflag\n");
			break;
		}
		int readLength = 0;
		struct sockaddr_in clientAddr;
		socklen_t len = sizeof(clientAddr);
		readLength = recvfrom(RecvSocket, recvBuf, 1500, 0, (struct sockaddr*)&clientAddr, &len);

		if (readLength == -1) {
			perror( "recvfrom ");
			//				_print_log("recvfrom failed with error %d\n", WSAGetLastError());
			continue;
		}
		else if(readLength == 0)
		{
			_print_log("End of stream.\n");

			break;
		}
		else
		{

		}
		readLength -= 12;
		progress += readLength;
		PSPacketBuffer *buffer;
		lfds611_queue_use(qs_pool);
		while(LFDS_SUCCESS != lfds611_queue_dequeue( qs_pool, (void **) &buffer))
		{
			if(recvThreadRunning != true)
				return;
			printf("dequeue failed\n");
			_print_log("dequeue failed\n");
			//lostPacket ++;
			Sleep(NORMAL_WAIT_TIME);
		}
		memcpy(buffer->packetBuffer, recvBuf + 12, readLength);
		buffer->bufferSize = readLength;
		lfds611_queue_use(qs_packet);
		while(LFDS_SUCCESS != lfds611_queue_enqueue( qs_packet, (void *) buffer))
		{
			if(recvThreadRunning != true)
				return;
			lostPacket ++;
			Sleep(NORMAL_WAIT_TIME);
		}
	}
	return;
}
void DHDecoder::startDecodeThread()
{
	while(qs_pool == NULL || qs_packet == NULL)
		Sleep(NORMAL_WAIT_TIME * 100);
	av_register_all();
	avformat_network_init();
	frame = avcodec_alloc_frame();
	if(frame == NULL)
	{
		_print_log("could not allocate video frame\n");
	}
	frameBGR = avcodec_alloc_frame();
	if(frameBGR == NULL)
	{
		_print_log("could not allocate video frame\n");
	}

	if(DHport == -1)
	{
		PLAY_GetFreePort(&DHport);
		if(!PLAY_SetStreamOpenMode(DHport, STREAME_REALTIME))
			_print_log("SetStreamOpenMode failed with retcode %d\n", PLAY_GetLastError(DHport));
		if(!PLAY_SetDecCallBackEx(DHport,DHDecCBFun,this))
			_print_log("SetDecCallBack failed with retcode %d\n", PLAY_GetLastError(DHport));

		DHInputThread = (HANDLE)_beginthreadex(NULL, 0, DHInputRoutine, this, 0, NULL);
	}

	return;
}
#else
#endif
